﻿using MongoDB.Driver;
using Newtonsoft.Json;
using Sustainalytics.Auth.Claims;
using Sustainalytics.ClientDW.Entities;
using Sustainalytics.Entities.ConnectionStrings;
using Sustainalytics.Replication.Publisher;
using Sustainalytics.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Claims;
using System.Web.Http;
using System.Web.Http.Cors;
using WebApi.OutputCache.V2;

namespace Sustainalytics.MostRecentActivity.Service.Controllers
{
    [EnableCors(origins: "*", headers: "*", methods: "*")]
    [RoutePrefix("api/v1/MostRecentActivity")]
    public class MostRecentActivityController : ApiController
    {
        private readonly ConnectionStrings _connectionString = null;
        private readonly IMongoCollection<Entities.MostRecentActivity> _mostRecentActivityCollection = null;
        private readonly IMongoCollection<CorporateData> _corporateDataCollection = null;
        private readonly ServiceBusPublisher _serviceBusPublisher = null;


        public MostRecentActivityController(
            ConnectionStrings connectionString,
            ServiceBusPublisher serviceBusPublisher,
            IMongoCollection<Entities.MostRecentActivity> mostRecentActivityCollection,
            IMongoCollection<CorporateData> corporateDataCollection)
        {
            _connectionString = connectionString;
            _mostRecentActivityCollection = mostRecentActivityCollection;
            _corporateDataCollection = corporateDataCollection;
            _serviceBusPublisher = serviceBusPublisher;
        }

        [Route("")]
        public HttpResponseMessage Get([FromUri] ListOptions listOptions)
        {
            if (ClaimsPrincipal.Current == null || ClaimsPrincipal.Current.Claims == null)
                return Request.CreateResponse(HttpStatusCode.Unauthorized, new { errCode = "ClaimsMissingException", message = "" });

            var claim = ClaimsPrincipal.Current.Claims.FirstOrDefault(c => c.Type == CustomClaimTypes.UserId);
            if (claim == null)
                return Request.CreateResponse(HttpStatusCode.NotFound);

            if (!Guid.TryParse(claim.Value, out Guid userId))
                return Request.CreateResponse(HttpStatusCode.NotFound);


            var accountUniverses = ClaimsPrincipal.Current.Claims.GetUniverseIds().Distinct().ToList();

            listOptions = listOptions ?? ListOptions.Default;

            var companiesIds = _corporateDataCollection
                .Find(Builders<CorporateData>.Filter.AnyIn(x => x.UniverseIds, accountUniverses))
                .Project<CorporateData>(Builders<CorporateData>.Projection.Include(x => x.Id))
                .ToList()
                .Select(x=> x.Id);

            var mostRecentActivities = _mostRecentActivityCollection
                .Find(x => companiesIds.Contains(x.CompanyId) && x.UserId == userId)
                .SortByDescending(x => x.LastAccessedDate)
                .Skip(listOptions.Skip)
                .Limit(listOptions.Take)
                .ToList();

            var result = mostRecentActivities.Select(e => MostRecentActivitytDto.FromMostRecentActivity(e)).ToList();

            return Request.CreateResponse(HttpStatusCode.OK, result);
        }

        [Route("{companyId}")]
        public HttpResponseMessage Post(Guid companyId)
        {

            if (ClaimsPrincipal.Current == null || ClaimsPrincipal.Current.Claims == null)
                return Request.CreateResponse(HttpStatusCode.Unauthorized, new { errCode = "ClaimsMissingException", message = "" });

            var claim = ClaimsPrincipal.Current.Claims.FirstOrDefault(c => c.Type == CustomClaimTypes.UserId);
            if (claim == null)
                return Request.CreateResponse(HttpStatusCode.NotFound);

            if (!Guid.TryParse(claim.Value, out Guid userId))
                return Request.CreateResponse(HttpStatusCode.NotFound);

            var accountUniverses = ClaimsPrincipal.Current.Claims.GetUniverseIds().Distinct().ToList();

            try
            {
                var corporateData = GetCorporateData(companyId, accountUniverses);
                if (corporateData == null)
                    return Request.CreateErrorResponse(HttpStatusCode.NotFound, "The company was not found!");


                var mostRecentActivity = _mostRecentActivityCollection
                    .Find(x => x.CompanyId == corporateData.Id && x.UserId == userId)
                    .FirstOrDefault();

                if (mostRecentActivity != null)
                {
                    _mostRecentActivityCollection.UpdateOne(x => x.Id == mostRecentActivity.Id,
                        Builders<Entities.MostRecentActivity>.Update.Set(x => x.LastAccessedDate, DateTime.UtcNow));
                    return Request.CreateResponse(HttpStatusCode.OK);
                }
                else
                {
                    mostRecentActivity = new Entities.MostRecentActivity()
                    {
                        CompanyId = companyId,
                        UserId = userId
                    };
                }

                var tickerAndExchange = string.Empty;
                if (!string.IsNullOrWhiteSpace(corporateData.MainTicker))
                    tickerAndExchange = corporateData.MainTicker;
                else if (!string.IsNullOrWhiteSpace(corporateData.MainExchange) && !string.IsNullOrWhiteSpace(corporateData.MainTicker))
                    tickerAndExchange = $"{corporateData.MainExchange}:{corporateData.MainTicker}";

                mostRecentActivity.CompanyTicker = tickerAndExchange;
                mostRecentActivity.UniverseIds = corporateData.UniverseIds;
                mostRecentActivity.CompanyName = corporateData.CompanyName;
                mostRecentActivity.CompanyNameUrlFriendly = corporateData.CompanyNameUrlFriendly;
                mostRecentActivity.LastAccessedDate = DateTime.UtcNow;

                _serviceBusPublisher.SendMessage(
                    JsonConvert.SerializeObject(mostRecentActivity),
                    ReplicationUtils.EntityType.MostRecentActivity,
                    ReplicationUtils.Operation.SaveMostRecentActivity);


                _mostRecentActivityCollection.InsertOne(mostRecentActivity);

                return Request.CreateResponse(HttpStatusCode.OK);
            }
            finally
            {
                var cache = Configuration.CacheOutputConfiguration().GetCacheOutputProvider(Request);
                cache.RemoveStartsWith(Configuration.CacheOutputConfiguration().MakeBaseCachekey("MostRecentActivity", "Get"));
            }
        }

        private CorporateData GetCorporateData(Guid companyId, List<int> accountUniverses)
        {
            return _corporateDataCollection
                                  .Find(Builders<CorporateData>.Filter.And(
                                      new List<FilterDefinition<CorporateData>>() {
                              Builders<CorporateData>.Filter.AnyIn(x => x.UniverseIds, accountUniverses),
                              Builders<CorporateData>.Filter.Eq(x => x.Id, companyId)
                                      }))
                                  .Project<CorporateData>(Builders<CorporateData>.Projection
                                    .Include(x => x.Id)
                                    .Include(x => x.MainTicker)
                                    .Include(x => x.MainExchange)
                                    .Include(x => x.UniverseIds)
                                    .Include(x => x.CompanyName)
                                    .Include(x => x.CompanyNameUrlFriendly))
                                  .FirstOrDefault();
        }
    }
}
